package com.molichuxing.gateway.utils.redis;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.molichuxing.framework.contants.RedisKeyConst;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.result.ResponseCodeEnum;
import com.molichuxing.framework.utils.DateUtil;
import com.molichuxing.framework.utils.Md5Util;
import com.molichuxing.framework.utils.RedisUtil;
import com.molichuxing.gateway.bff.user.entity.response.AccountVo;
import com.molichuxing.gateway.bff.user.entity.response.UserVo;
import com.molichuxing.gateway.property.UserTypeEnum;

/**
 * 用户token工具类
 * 
 * @author zoumingyu
 * @date 2019年8月19日
 *
 */
@Component
public class TokenUtil {
	private static final Logger logger = LoggerFactory.getLogger(TokenUtil.class);

	// 环境
	@Value("${profiles.active}")
	private String active;

	// token有效时间(7天)
	@Value("${token.valid.time}")
	private Integer tokenTime;

	@Resource
	private RedisUtil redisUtil;

	/**
	 * 设置用户token
	 * 
	 * @param user
	 *            用户信息
	 */
	public String setUserToken(UserVo user) {
		// 生成token(TOKEN_KEY+MD5_16bit(环境).MD5_16bit((用户账号+用户名).MD5_16bit((当前时间+随机数))
		String date = DateUtil.formatTime(LocalDateTime.now());
		String tokenPhone = RedisKeyConst.TOKEN_MOBILE_KEY + Md5Util.md5Hex(active + UserTypeEnum.APP_USER.getName())
				+ "." + Md5Util.md5Hex(user.getPhone());
		String token = tokenPhone + "." + Md5Util.md5Hex(date + Math.random());
		List<String> list = redisUtil.scan(tokenPhone + "*");
		if (list.size() > 0) {
			list.forEach(key -> redisUtil.del(key));
		}
		redisUtil.setex(token, JSONObject.toJSONString(user), tokenTime);
		return token.replace(RedisKeyConst.TOKEN_MOBILE_KEY, "");
	}

	/**
	 * 设置用户token
	 * 
	 * @param user
	 *            用户信息
	 */
	public void modifyUserToken(UserVo user) {
		// 生成token(TOKEN_KEY+MD5_16bit(环境).MD5_16bit((用户账号+用户名).MD5_16bit((当前时间+随机数))
		String tokenPhone = RedisKeyConst.TOKEN_MOBILE_KEY + Md5Util.md5Hex(active + UserTypeEnum.APP_USER.getName())
				+ "." + Md5Util.md5Hex(user.getPhone());
		List<String> list = redisUtil.scan(tokenPhone + "*");
		if (list.size() > 0) {
			redisUtil.setex(list.get(0), JSONObject.toJSONString(user), tokenTime);
		}

	}

	/**
	 * 设置用户token
	 * 
	 * @param user
	 *            用户信息
	 */
	public void modifyWechatUserToken(UserVo user) {
		// 生成token(TOKEN_KEY+MD5_16bit(环境).MD5_16bit((用户账号+用户名).MD5_16bit((当前时间+随机数))
		String tokenPhone = RedisKeyConst.TOKEN_MOBILE_KEY + Md5Util.md5Hex(active + UserTypeEnum.WECHAT_USER.getName())
				+ "." + Md5Util.md5Hex(user.getPhone());
		List<String> list = redisUtil.scan(tokenPhone + "*");
		if (list.size() > 0) {
			redisUtil.setex(list.get(0), JSONObject.toJSONString(user), tokenTime);
		}

	}

	/**
	 * 设置用户(智能终端)token
	 * 
	 * @param user
	 *            用户信息
	 */
	public String setTerminalUserToken(UserVo user) {
		// 生成token(TOKEN_KEY+MD5_16bit(环境).MD5_16bit((用户账号+用户名).MD5_16bit((当前时间+随机数))
		String date = DateUtil.formatTime(LocalDateTime.now());
		String tokenIdNumber = RedisKeyConst.TOKEN_MOBILE_KEY + Md5Util.md5Hex(active + UserTypeEnum.APP_USER.getName())
				+ "." + Md5Util.md5Hex(user.getIdNumber());
		String token = tokenIdNumber + "." + Md5Util.md5Hex(date + Math.random());
		List<String> list = redisUtil.scan(tokenIdNumber + "*");
		if (list.size() > 0) {
			list.forEach(key -> redisUtil.del(key));
		}
		redisUtil.setex(token, JSONObject.toJSONString(user), getTime());
		return token.replace(RedisKeyConst.TOKEN_MOBILE_KEY, "");
	}

	/**
	 * 设置用户(微信)token
	 * 
	 * @param user
	 * @param openId
	 *            用户信息
	 */
	public String setWechatUserToken(UserVo user, String openId) {
		// 生成token(TOKEN_KEY+MD5_16bit(环境).MD5_16bit((用户账号+用户名).MD5_16bit((当前时间+随机数))
		String date = DateUtil.formatTime(LocalDateTime.now());
		String tokenOpenId = RedisKeyConst.TOKEN_MOBILE_KEY
				+ Md5Util.md5Hex(active + UserTypeEnum.WECHAT_USER.getName()) + "." + Md5Util.md5Hex(user.getPhone());
		String token = tokenOpenId + "." + Md5Util.md5Hex(date + Math.random());
		List<String> list = redisUtil.scan(tokenOpenId + "*");
		if (list.size() > 0) {
			list.forEach(key -> redisUtil.del(key));
		}
		redisUtil.setex(token, JSONObject.toJSONString(user), tokenTime);
		return token.replace(RedisKeyConst.TOKEN_MOBILE_KEY, "");
	}

	/**
	 * 设置用户(智能终端销售顾问)token
	 * 
	 * @param user
	 *            用户信息
	 */
	public String setCounselorUserToken(AccountVo accountVo) {
		// 生成token(TOKEN_KEY+MD5_16bit(环境).MD5_16bit((用户账号+用户名).MD5_16bit((当前时间+随机数))
		String date = DateUtil.formatTime(LocalDateTime.now());
		String tokenPhone = RedisKeyConst.TOKEN_COUNSELOR_KEY
				+ Md5Util.md5Hex(active + UserTypeEnum.COUNSELOR_USER.getName()) + "."
				+ Md5Util.md5Hex(accountVo.getId() + accountVo.getUserPhone());
		String token = tokenPhone + "." + Md5Util.md5Hex(date + Math.random());
		List<String> list = redisUtil.scan(tokenPhone + "*");
		if (list.size() > 0) {
			list.forEach(key -> redisUtil.del(key));
		}
		redisUtil.setex(token, JSONObject.toJSONString(accountVo), getTime());
		return token.replace(RedisKeyConst.TOKEN_COUNSELOR_KEY, "");
	}

	/**
	 * 获取当天结束时间 相差时长
	 * 
	 * @return
	 */
	private Integer getTime() {
		LocalDateTime now = LocalDateTime.now();
		LocalDateTime dayEnd = DateUtil.getDayEnd(now);
		Duration between = java.time.Duration.between(now, dayEnd);
		long millis = between.toMillis();
		long second = millis / 1000;
		return (int) second;
	}

	/**
	 * 更新用户信息
	 * 
	 * @param terminalToken
	 * @param user
	 * 
	 * @return
	 */
	public void setTerminalUser(String terminalToken, UserVo user) {
		terminalToken = RedisKeyConst.TOKEN_MOBILE_KEY + terminalToken;
		redisUtil.setex(terminalToken, JSONObject.toJSONString(user), getTime());
	}

	/**
	 * 更新用户信息
	 * 
	 * @param token
	 * @param user
	 * 
	 * @return
	 */
	public void setUser(String token, UserVo user) {
		token = RedisKeyConst.TOKEN_MOBILE_KEY + token;
		redisUtil.setex(token, JSONObject.toJSONString(user), tokenTime);
	}

	/**
	 * 获取用户信息
	 * 
	 * @param token
	 *            token
	 * @return
	 */
	public UserVo getUser(String token) {
		String user = null;
		try {
			user = redisUtil.get(RedisKeyConst.TOKEN_MOBILE_KEY + token);
		} catch (Exception e) {
			logger.error("获取用户信息异常:", e);
		}
		return user == null ? null : JSONObject.parseObject(user, UserVo.class);
	}

	/**
	 * 获取销售顾问用户信息(终端)
	 * 
	 * @param counselorToken
	 *            counselorToken
	 * @return
	 */
	public AccountVo getCounselorUser(String counselorToken) {
		String accountVo = null;
		try {
			accountVo = redisUtil.get(RedisKeyConst.TOKEN_COUNSELOR_KEY + counselorToken);
		} catch (Exception e) {
			logger.error("获取销售顾问用户信息异常:", e);
		}
		return accountVo == null ? null : JSONObject.parseObject(accountVo, AccountVo.class);
	}

	/**
	 * 获取用户信息
	 * 
	 * @param token
	 *            token
	 * @return
	 */
	public UserVo getUserVo(String token) {
		String user = redisUtil.get(RedisKeyConst.TOKEN_MOBILE_KEY + token);
		UserVo userVo = user == null ? null : JSONObject.parseObject(user, UserVo.class);
		if (null == userVo) {
			throw new BizException(ResponseCodeEnum.LOGIN_ERROR.getCode(), ResponseCodeEnum.LOGIN_ERROR.getMessage());
		}
		return userVo;
	}

	/**
	 * 刷新token
	 * 
	 * @param token
	 */
	public void refresh(String token) {
		try {
			redisUtil.expire(RedisKeyConst.TOKEN_MOBILE_KEY + token, tokenTime);
		} catch (Exception e) {
			logger.error("刷新token异常:", e);
		}
	}

	/**
	 * 刷新terminalToken
	 * 
	 * @param terminalToken
	 */
	public void refreshTerminal(String terminalToken) {
		try {
			redisUtil.expire(RedisKeyConst.TOKEN_MOBILE_KEY + terminalToken, getTime());
		} catch (Exception e) {
			logger.error("刷新token异常:", e);
		}
	}

	/**
	 * 删除token
	 * 
	 * @param token
	 */
	public Boolean logOut(String token) {
		token = RedisKeyConst.TOKEN_MOBILE_KEY + token;
		List<String> list = redisUtil.scan(token + "*");
		if (list.size() > 0) {
			list.forEach(key -> redisUtil.del(key));
		}
		return true;
	}
}
